package io.gitee.zhangbinhub.admin.controller.api

import io.gitee.zhangbinhub.acp.boot.exceptions.WebException
import io.gitee.zhangbinhub.acp.boot.log.LogAdapter
import io.gitee.zhangbinhub.acp.core.common.CommonTools
import io.gitee.zhangbinhub.admin.api.ServerApi
import io.gitee.zhangbinhub.admin.base.BaseController
import io.gitee.zhangbinhub.admin.constant.OauthConstant
import io.gitee.zhangbinhub.admin.constant.UserConfigExpression
import io.gitee.zhangbinhub.admin.entity.User
import io.gitee.zhangbinhub.admin.po.UserInfoPo
import io.gitee.zhangbinhub.admin.po.UserPo
import io.gitee.zhangbinhub.admin.po.UserQueryPo
import io.gitee.zhangbinhub.admin.service.RuntimeConfigService
import io.gitee.zhangbinhub.admin.service.UserService
import io.gitee.zhangbinhub.admin.vo.CustomerQueryPageVo
import io.gitee.zhangbinhub.admin.vo.InfoVo
import io.gitee.zhangbinhub.admin.vo.UserVo
import io.swagger.v3.oas.annotations.*
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.responses.ApiResponses
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.validation.Valid
import jakarta.validation.constraints.NotBlank
import jakarta.validation.constraints.NotEmpty
import jakarta.validation.constraints.NotNull
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.domain.Page
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*

/**
 * @author zhangbin by 11/04/2018 16:04
 * @since JDK 11
 */
@Validated
@RestController
@RequestMapping(ServerApi.basePath)
@Tag(name = "用户信息")
class UserController @Autowired
constructor(
    logAdapter: LogAdapter,
    private val userService: UserService,
    private val runtimeConfigService: RuntimeConfigService
) : BaseController(logAdapter) {

    @Operation(
        summary = "获取当前用户信息",
        description = "根据当前登录的用户信息，并查询详细信息，包含用户基本信息、所属角色、所属机构"
    )
    @ApiResponses(ApiResponse(responseCode = "400", description = "找不到用户信息"))
    @GetMapping(value = [ServerApi.currUser], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun userInfo(@Parameter(hidden = true) bearerTokenAuthentication: BearerTokenAuthentication): ResponseEntity<User> =
        (userService.getUserInfoByLoginNo(bearerTokenAuthentication.name)?.apply {
            if (this.lastUpdatePasswordTime == null) {
                this.passwordExpire = true
            } else {
                runtimeConfigService.findByName(OauthConstant.passwordUpdateIntervalTime)?.let { runtimeConfig ->
                    if (runtimeConfig.enabled && !CommonTools.isNullStr(runtimeConfig.value)) {
                        this.passwordExpire =
                            (System.currentTimeMillis() - this.lastUpdatePasswordTime!! - runtimeConfig.value!!.toLong()) >= 0
                    }
                }
            }
        } ?: throw WebException("找不到用户信息")).let { ResponseEntity.ok(it) }

    @Operation(
        summary = "更新当前用户信息",
        description = "1、根据当前登录的用户信息，更新头像、名称、手机；2、如果原密码和新密码均不为空，校验原密码并修改为新密码"
    )
    @ApiResponses(
        ApiResponse(
            responseCode = "400",
            description = "参数校验不通过；找不到用户信息；原密码不正确；新密码为空；"
        )
    )
    @RequestMapping(
        value = [ServerApi.currUser],
        method = [RequestMethod.PUT, RequestMethod.PATCH],
        produces = [MediaType.APPLICATION_JSON_VALUE]
    )
    @Throws(WebException::class)
    fun updateCurrUser(
        @Parameter(hidden = true) bearerTokenAuthentication: BearerTokenAuthentication,
        @RequestBody @Valid userInfoPo: UserInfoPo
    ): ResponseEntity<User> {
        val userInfo =
            userService.getUserInfoByLoginNo(bearerTokenAuthentication.name) ?: throw WebException("找不到用户信息")
        userInfo.avatar = userInfoPo.avatar ?: ""
        userInfo.name = userInfoPo.name ?: userInfo.name
        userInfo.mobile = userInfoPo.mobile ?: userInfo.mobile
        if (!CommonTools.isNullStr(userInfoPo.oldPassword)) {
            if (CommonTools.isNullStr(userInfoPo.password)) {
                throw WebException("新密码为空")
            }
            if (userInfo.password.equals(userInfoPo.oldPassword!!, ignoreCase = true)) {
                userInfo.password = userInfoPo.password!!
                userInfo.lastUpdatePasswordTime = System.currentTimeMillis()
            } else {
                throw WebException("原密码不正确")
            }
        }
        return ResponseEntity.ok(userService.doSaveUser(userInfo))
    }

    @Operation(summary = "获取可管理的用户信息列表", description = "根据当前登录的用户信息，获取可管理的用户信息列表")
    @ApiResponses(ApiResponse(responseCode = "400", description = "找不到用户信息"))
    @PreAuthorize(UserConfigExpression.userConfig)
    @GetMapping(value = [ServerApi.modifiableUser], produces = [MediaType.APPLICATION_JSON_VALUE])
    fun modifiableUser(@Parameter(hidden = true) bearerTokenAuthentication: BearerTokenAuthentication): ResponseEntity<List<UserVo>> =
        ResponseEntity.ok(userService.findModifiableUserList(bearerTokenAuthentication.name))

    @Operation(
        summary = "新建用户信息",
        description = "名称、登录账号、手机号、级别、序号、是否启用、关联机构、管理机构、关联角色"
    )
    @ApiResponses(
        ApiResponse(responseCode = "201", description = "创建成功"),
        ApiResponse(responseCode = "400", description = "参数校验不通过；角色编码非法，请重新输入；")
    )
    @PreAuthorize(UserConfigExpression.userAdd)
    @PutMapping(value = [ServerApi.userConfig], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun add(
        @Parameter(hidden = true) bearerTokenAuthentication: BearerTokenAuthentication,
        @RequestBody @Valid userPo: UserPo
    ): ResponseEntity<User> =
        userService.doCreate(bearerTokenAuthentication.name, userPo).let {
            ResponseEntity.status(HttpStatus.CREATED).body(it)
        }

    @Operation(summary = "删除指定的用户信息")
    @ApiResponses(ApiResponse(responseCode = "400", description = "参数校验不通过；没有权限做此操作；"))
    @PreAuthorize(UserConfigExpression.userDelete)
    @DeleteMapping(value = [ServerApi.userConfig], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun delete(
        @Parameter(hidden = true) bearerTokenAuthentication: BearerTokenAuthentication,
        @Parameter(description = "id列表", required = true)
        @NotEmpty(message = "id不能为空")
        @NotNull(message = "id不能为空")
        @RequestBody
        idList: MutableList<String>
    ): ResponseEntity<InfoVo> {
        userService.doDelete(bearerTokenAuthentication.name, idList)
        return ResponseEntity.ok(InfoVo(message = "删除成功"))
    }

    @Operation(summary = "更新用户信息", description = "名称、手机号、级别、序号、是否启用、关联机构、管理机构、关联角色")
    @ApiResponses(
        ApiResponse(
            responseCode = "400",
            description = "参数校验不通过；角色编码非法，请重新输入；没有权限做此操作；ID不能为空；找不到信息；"
        )
    )
    @PreAuthorize(UserConfigExpression.userUpdate)
    @PatchMapping(value = [ServerApi.userConfig], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun update(
        @Parameter(hidden = true) bearerTokenAuthentication: BearerTokenAuthentication,
        @RequestBody @Valid userPo: UserPo
    ): ResponseEntity<User> {
        if (CommonTools.isNullStr(userPo.id)) {
            throw WebException("ID不能为空")
        }
        return ResponseEntity.ok(userService.doUpdate(bearerTokenAuthentication.name, userPo))
    }

    @Operation(summary = "重置用户密码", description = "根据用户ID查询详细信息并重置密码")
    @ApiResponses(ApiResponse(responseCode = "400", description = "找不到信息；"))
    @PreAuthorize(UserConfigExpression.userUpdate)
    @GetMapping(value = [ServerApi.userResetPwd + "/{userId}"], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun resetPwd(
        @Parameter(hidden = true) bearerTokenAuthentication: BearerTokenAuthentication,
        @PathVariable(name = "userId") userId: String
    ): ResponseEntity<InfoVo> {
        userService.doUpdatePwd(bearerTokenAuthentication.name, userId)
        return ResponseEntity.ok(InfoVo(message = "操作成功"))
    }

    @Operation(summary = "查询用户列表", description = "查询条件：名称、登录帐号、状态、所属机构")
    @ApiResponses(ApiResponse(responseCode = "400", description = "参数校验不通过；"))
    @PreAuthorize(UserConfigExpression.userQuery)
    @PostMapping(value = [ServerApi.userConfig], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun query(@RequestBody @Valid userQueryPo: UserQueryPo): ResponseEntity<CustomerQueryPageVo<UserVo>> =
        ResponseEntity.ok(userService.doQuery(userQueryPo))

    @Operation(summary = "查询用户信息（用户ID）", description = "根据用户ID查询详细信息")
    @ApiResponses(ApiResponse(responseCode = "400", description = "找不到信息；"))
    @PreAuthorize(UserConfigExpression.userQuery)
    @GetMapping(value = [ServerApi.userConfig + "/{userId}"], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun getUserInfo(@PathVariable(name = "userId") userId: String): ResponseEntity<User> =
        (userService.getUserInfoById(userId) ?: throw WebException("找不到用户信息")).let { ResponseEntity.ok(it) }

    @Operation(summary = "查询用户信息（登录账号）", description = "根据用户登录账号查询详细信息")
    @ApiResponses(ApiResponse(responseCode = "400", description = "找不到信息；"))
    @GetMapping(value = [ServerApi.userConfig], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun getUserInfoByLoginNo(
        @Parameter(description = "登录账号", required = true)
        @NotBlank(message = "登录账号不能为空")
        @RequestParam(name = "loginNo") loginNo: String
    ): ResponseEntity<UserVo> =
        userService.getUserVoByLoginNo(loginNo).let { ResponseEntity.ok(it) }

    @Operation(summary = "通过登录号或姓名，查询用户列表")
    @PreAuthorize(UserConfigExpression.userQuery)
    @GetMapping(value = [ServerApi.userList + "-by-code-or-name"], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun getUserListByLoginNoOrName(
        @Parameter(description = "登录号或姓名", required = true)
        @NotBlank(message = "登录号或姓名不能为空")
        @RequestParam(name = "loginNoOrName") loginNoOrName: String
    ): ResponseEntity<List<UserVo>> =
        ResponseEntity.ok(userService.getUserVoListByLoginNoOrName(loginNoOrName, false))

    @Operation(summary = "通过角色编码，查询当前机构下的用户列表")
    @PreAuthorize(UserConfigExpression.userQuery)
    @GetMapping(
        value = [ServerApi.currOrgUserList],
        params = ["!orgLevel", "roleCode"],
        produces = [MediaType.APPLICATION_JSON_VALUE]
    )
    @Throws(WebException::class)
    fun getUserListByCurrOrgAndRole(
        @Parameter(hidden = true) bearerTokenAuthentication: BearerTokenAuthentication,
        @Parameter(description = "角色编码", required = true)
        @NotBlank(message = "角色编码不能为空")
        @RequestParam(name = "roleCode") roleCode: String
    ): ResponseEntity<List<UserVo>> =
        ResponseEntity.ok(
            userService.getUserVoListByRelativeOrgAndRole(
                bearerTokenAuthentication.name,
                listOf(0),
                roleCode.split(",")
            )
        )

    @Operation(summary = "通过相对机构级别和角色编码，查询用户列表")
    @PreAuthorize(UserConfigExpression.userQuery)
    @GetMapping(
        value = [ServerApi.currOrgUserList],
        params = ["orgLevel", "roleCode"],
        produces = [MediaType.APPLICATION_JSON_VALUE]
    )
    @Throws(WebException::class)
    fun getUserListByRelativeOrgAndRole(
        @Parameter(hidden = true) bearerTokenAuthentication: BearerTokenAuthentication,
        @Parameter(description = "机构层级", required = true)
        @NotBlank(message = "机构层级不能为空")
        @RequestParam(name = "orgLevel") orgLevel: String,
        @Parameter(description = "角色编码", required = true)
        @NotBlank(message = "角色编码不能为空")
        @RequestParam(name = "roleCode") roleCode: String
    ): ResponseEntity<List<UserVo>> =
        ResponseEntity.ok(
            userService.getUserVoListByRelativeOrgAndRole(
                bearerTokenAuthentication.name,
                orgLevel.split(",").map { item -> item.toInt() },
                roleCode.split(",")
            )
        )

    @Operation(summary = "通过机构编码和角色编码，查询用户列表")
    @PreAuthorize(UserConfigExpression.userQuery)
    @GetMapping(
        value = [ServerApi.userList],
        params = ["orgCode", "roleCode"],
        produces = [MediaType.APPLICATION_JSON_VALUE]
    )
    @Throws(WebException::class)
    fun getUserListByOrgCodeAndRole(
        @Parameter(description = "机构编码", required = true)
        @NotBlank(message = "机构编码不能为空")
        @RequestParam(name = "orgCode") orgCode: String,
        @Parameter(description = "角色编码", required = true)
        @NotBlank(message = "角色编码不能为空")
        @RequestParam(name = "roleCode") roleCode: String
    ): ResponseEntity<List<UserVo>> =
        ResponseEntity.ok(userService.getUserVoListByOrgCodeAndRole(orgCode.split(","), roleCode.split(",")))

    @Operation(summary = "通过角色编码，查询用户列表")
    @PreAuthorize(UserConfigExpression.userQuery)
    @GetMapping(
        value = [ServerApi.userList],
        params = ["!orgCode", "roleCode"],
        produces = [MediaType.APPLICATION_JSON_VALUE]
    )
    @Throws(WebException::class)
    fun getUserListByRole(
        @Parameter(description = "角色编码", required = true)
        @NotBlank(message = "角色编码不能为空")
        @RequestParam(name = "roleCode") roleCode: String
    ): ResponseEntity<List<UserVo>> =
        ResponseEntity.ok(userService.getUserVoListByRole(roleCode.split(",")))
}
